package com.sc.nft.annotation;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.sc.nft.constant.DistributedLockConstant;
import com.sc.nft.util.AnnotationResolver;
import com.sc.nft.util.RedisKeyUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;


@Aspect
@Component
@Slf4j
public class DistributedLockHandler {

    @Resource
    private RedissonLock redissonLock;


    @Around("@annotation(distributedLock)")
    @SneakyThrows
    public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) {
        final long snowFlake = IdUtil.getSnowflake().nextId();
        log.info("[开始]执行RedisLock环绕通知,获取Redis分布式锁开始");
        // 获取锁名称
        Object[] resolver = AnnotationResolver.newInstance().resolver(joinPoint, distributedLock.value());
        // 通过前端的key,获取对应的参数以及对应的key,并且进行拼接组装
        String lockName = RedisKeyUtil.redisKeyAssemble(resolver, distributedLock.segmentation());
        // 锁是否自动延期
        boolean postPone = distributedLock.isPostPone();
        // 锁的模式
        int pattern = distributedLock.pattern();
        // 根据锁的模式进行判断
        if (DistributedLockConstant.LOCK == pattern) {
            if (postPone) {
                // 自动延期
                redissonLock.lock(lockName);
            } else {
                //获取超时时间，默认10秒
                int leaseTime = distributedLock.leaseTime();
                redissonLock.lock(lockName, leaseTime);
            }
        }
        boolean is = false;
        if (DistributedLockConstant.TRY_LOCK == pattern) {
            if (postPone) {
                // 自动延期
                is = redissonLock.tryLock(lockName, distributedLock.waitTime());
            } else {
                //获取超时时间，默认10秒,等待时间需要设置,默认是0
                is = redissonLock.tryLock(lockName, distributedLock.leaseTime(), distributedLock.waitTime());
            }
        }
        try {
            log.info("获取Redis分布式锁[成功]，加锁完成，开始执行业务逻辑...");
            log.info(StrUtil.format("锁名称:{},锁标识位:{}", lockName, snowFlake));
            if (DistributedLockConstant.LOCK == pattern) {
                return joinPoint.proceed();
            }
            if (DistributedLockConstant.TRY_LOCK == pattern) {
                // 如果为true证明获取到锁了,如果为false则锁获取失败.
                if (is) {
                    return joinPoint.proceed();
                } else {
                    throw new Exception(distributedLock.message());
                }
            }
        } finally {
            // 如果该线程还持有该锁，那么释放该锁。如果该线程不持有该锁，说明该线程的锁已到过期时间，自动释放锁
            if (redissonLock.isHeldByCurrentThread(lockName)) {
                redissonLock.unlock(lockName);
            }
            log.info(StrUtil.format("锁释放:{},锁标识位:{}", lockName, snowFlake));
            log.info("释放Redis分布式锁[成功]，解锁完成，结束业务逻辑...");
        }
        return null;
    }
}